/**
 *
 */
package info.touret.winecellar.bottle.client;

import static info.touret.winecellar.dao.client.Constants.PAGE_SIZE;
import info.touret.winecellar.bottle.shared.UserInfoProxy;
import info.touret.winecellar.bottle.shared.TastingProxy;
import info.touret.winecellar.producer.client.ProducerRequestFactory;
import info.touret.winecellar.producer.shared.ProducerProxy;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Set;
import java.util.logging.Logger;

import javax.inject.Inject;

import com.google.gwt.activity.shared.Activity;
import com.google.gwt.cell.client.CheckboxCell;
import com.google.gwt.cell.client.DatePickerCell;
import com.google.gwt.cell.client.EditTextCell;
import com.google.gwt.cell.client.FieldUpdater;
import com.google.gwt.cell.client.SelectionCell;
import com.google.gwt.cell.client.TextCell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.shared.EventBus;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.i18n.client.DateTimeFormat.PredefinedFormat;
import com.google.gwt.resources.client.CssResource;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiFactory;
import com.google.gwt.uibinder.client.UiField;
import com.google.gwt.uibinder.client.UiHandler;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.SimplePager;
import com.google.gwt.user.cellview.client.SimplePager.TextLocation;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.ui.AcceptsOneWidget;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.AsyncDataProvider;
import com.google.gwt.view.client.DefaultSelectionEventManager;
import com.google.gwt.view.client.HasData;
import com.google.gwt.view.client.MultiSelectionModel;
import com.google.gwt.view.client.ProvidesKey;
import com.google.gwt.view.client.SelectionModel;
import com.google.web.bindery.requestfactory.shared.EntityProxyChange;
import com.google.web.bindery.requestfactory.shared.Receiver;
import com.google.web.bindery.requestfactory.shared.Request;
import com.google.web.bindery.requestfactory.shared.ServerFailure;
import com.google.web.bindery.requestfactory.shared.Violation;

/**
 * Widget qui gere la liste des bouteilles ( affichage /suppression /note )
 * 
 * @author touret-a
 */
public class TastingListUI extends Composite implements
		EntityProxyChange.Handler<TastingProxy>, Activity {

	@UiField(provided = true)
	SimplePager pager = new SimplePager(TextLocation.CENTER);

	@Inject
	Logger trace;

	interface TastingListUIUiBinder extends UiBinder<Widget, TastingListUI> {
	}

	private static TastingListUIUiBinder uiBinder = GWT
			.create(TastingListUIUiBinder.class);

	/**
	 * Constructeur par defaut
	 */
	public TastingListUI() {
		initWidget(uiBinder.createAndBindUi(this));
	}

	/**
	 * A utiliser par defaut charge les differentes donnees
	 * 
	 * @param factory
	 * @param producerrequestfactory
	 */
	public TastingListUI(TastingRequestFactory _factory) {
		this();
		tastingRequestFactory = _factory;
		populateTable();
		createTable();
	}

	@UiField
	CellTable<TastingProxy> cellTable;

	private BottleRequestFactory bottlerequestFactory;
	private ProducerRequestFactory producerrequestFactory;
	private TastingRequestFactory tastingRequestFactory;

	@Override
	public String mayStop() {
		// TODO Auto-generated method stub
		return null;
	}

	@Override
	public void onCancel() {
		// TODO Auto-generated method stub

	}

	@Override
	public void onStop() {
		// TODO Auto-generated method stub

	}

	@Override
	public void start(AcceptsOneWidget panel, EventBus eventBus) {
		// TODO Auto-generated method stub

	}

	@Override
	public void onProxyChange(EntityProxyChange<TastingProxy> event) {

	}

	private Receiver<List<TastingProxy>> lastDataTastingReceiver;

	private List<TastingProxy> lastTastingsData;

	/**
	 * Peuple la table des bouteilles
	 */
	private void populateTable() {
		// provider asynchrone
		AsyncDataProvider<TastingProxy> dataProdiver = new AsyncDataProvider<TastingProxy>() {
			@Override
			protected void onRangeChanged(HasData<TastingProxy> display) {
				// final Range range = display.getVisibleRange();
				TastingRequest requestTastings = tastingRequestFactory
						.tastingRequest();
				final int start = display.getVisibleRange().getStart();
				final int displayLength = display.getVisibleRange().getLength();
				Request<List<TastingProxy>> getReq = requestTastings
						.findAllTastings();
				lastDataTastingReceiver = new Receiver<List<TastingProxy>>() {
					@Override
					public void onSuccess(List<TastingProxy> response) {
						GWT.log("****************************************************");
						GWT.log("---->taille de la reponse : "+response.size());
						GWT.log("---->display: "+displayLength);
						GWT.log("---->start: "+start);
						int end = start+displayLength ;
						if(start+PAGE_SIZE>response.size()){
							end=response.size();
						}
						GWT.log("---->fin calculée : "+end);
						GWT.log("---->début calculé : "+start);
						cellTable.setVisibleRange(start, end);
						updateRowCount(response.size(), true);
						updateRowData(start, response.subList(start, end));
					//	lastData = new ArrayList<TastingProxy>(response.subList(start, end));
						GWT.log("****************************************************");
					}
				};
				getReq.fire(lastDataTastingReceiver);
			}
		};
		dataProdiver.addDataDisplay(cellTable);
	}

	/**
	 * Mise a jour du tableau
	 * 
	 * @param event
	 */
	@UiHandler("updateButton")
	void onUpdatebuttonClick(ClickEvent event) {
		populateTable();
	}

	/**
	 * Provider des cles primaires des bouteilles presentes dans le tableau
	 */
	private static final ProvidesKey<TastingProxy> KEY_PROVIDER = new ProvidesKey<TastingProxy>() {
		public Object getKey(TastingProxy item) {
			return item.getId();
		}
	};

	/**
	 * Cree le tableau principal
	 */
	private void createTable() {
		/*
		 * Ce tableau gere la selection via un checkbox selection model Un CB
		 * est necessaire pour la suppression
		 */
		final SelectionModel<TastingProxy> checkboxSelectionModel = new MultiSelectionModel<TastingProxy>(
				KEY_PROVIDER);

		cellTable.setSelectionModel(checkboxSelectionModel,
				DefaultSelectionEventManager
						.<TastingProxy> createCheckboxManager());

		/**
		 * definitions des colonnes
		 * 
		 * */
		Column<TastingProxy, Boolean> checkColumn = new Column<TastingProxy, Boolean>(
				new CheckboxCell(true, false)) {
			@Override
			public Boolean getValue(TastingProxy object) {
				return checkboxSelectionModel.isSelected(object);
			}
		};
		cellTable.addColumn(checkColumn, SafeHtmlUtils.fromSafeConstant(""));
		final Receiver<Void> updateReceiver = new Receiver<Void>() {
			@Override
			public void onSuccess(Void response) {
			}

			@Override
			public void onFailure(ServerFailure error) {
				super.onFailure(error);
				Window.alert("La modification a echouee");
			}

			@Override
			public void onViolation(Set<Violation> errors) {
				Window.alert("La modification a echouee : Parametres incorrects");
			}
		};

		// NOM
		final EditTextCell nameCell = new EditTextCell();
		Column<TastingProxy, String> nameColumn = new Column<TastingProxy, String>(
				nameCell) {
			@Override
			public String getValue(TastingProxy object) {
				return object.getBottleName();
			}

		};
		cellTable.addColumn(nameColumn, "Nom");

		// nom de la bouteille
		final TextCell denominationCell = new TextCell();
		Column<UserInfoProxy, String> denominationColumn = new Column<UserInfoProxy, String>(
				denominationCell) {
			@Override
			public String getValue(UserInfoProxy object) {
				return object.getDenomination() == null ? "" : object
						.getDenomination();
			}

		};

		final SelectionCell quantityCell = new SelectionCell(NotesFactory
				.getFactory().getNotes());
		Column<TastingProxy, String> quantityColumn = new Column<TastingProxy, String>(
				quantityCell) {
			@Override
			public String getValue(TastingProxy object) {
				return object.getQuantity().toString();
			}

		};

		quantityColumn
				.setFieldUpdater(new FieldUpdater<TastingProxy, String>() {
					@Override
					public void update(int index, TastingProxy object,
							String value) {
						try {
							TastingRequest request = tastingRequestFactory
									.tastingRequest();
							TastingProxy proxy = request.edit(object);
							proxy.setQuantity(Integer.parseInt(value));
							request.update().using(proxy).fire(updateReceiver);
						} catch (Exception e) {
							GWT.log("erreur dans la mise a jour :", e);
						}
						return;
					}
				});
		cellTable.addColumn(quantityColumn, "Quantité");
		DateTimeFormat dateFormat = DateTimeFormat
				.getFormat(PredefinedFormat.DATE_SHORT);
		// producteur
		final DatePickerCell tastedCell = new DatePickerCell(dateFormat);

		Column<TastingProxy, Date> tastedColumn = new Column<TastingProxy, Date>(
				tastedCell) {
			@Override
			public Date getValue(TastingProxy object) {
				return object.getTasted();
			}

		};
		// date d acquisition
		tastedColumn.setFieldUpdater(new FieldUpdater<TastingProxy, Date>() {
			@Override
			public void update(int index, TastingProxy object, Date value) {
				TastingRequest request = tastingRequestFactory.tastingRequest();
				TastingProxy proxy = request.edit(object);
				proxy.setTasted(value);
				request.update().using(proxy).fire(updateReceiver);
				return;
			}
		});
		cellTable.addColumn(tastedColumn, "Dégusté le ");

		pager.setDisplay(cellTable);
		pager.setPageSize(PAGE_SIZE);
	}

	/**
	 * Supprime la ligne selectionnee du tableau
	 * 
	 * @param event
	 */
	@UiHandler("deleteButton")
	void onDeleteButtonClick(ClickEvent event) {
		deleteSelectedItems();
	}

	/**
	 * @TODO factoriser
	 */
	private void deleteSelectedItems() {
		if (lastDataTastingReceiver != null) {
			TastingRequest req = tastingRequestFactory.tastingRequest();
			for (TastingProxy current : lastTastingsData)
				if (cellTable.getSelectionModel().isSelected(current)) {
					TastingProxy toremove = req.edit(current);
					req.remove().using(toremove);
				}
			req.fire(new Receiver<Void>() {
				@Override
				public void onSuccess(Void response) {
					populateTable();
				}
			});
		}
	}

	@UiField
	Button updateButton;

	@UiField
	Button updateButton1;

	@UiField
	Button deleteButton;

	@UiField
	Button deleteButton1;

	/**
	 * MAJ le tableau
	 * 
	 * @param event
	 */
	@UiHandler("updateButton1")
	void onUpdatebutton1Click(ClickEvent event) {
		populateTable();
		// cellTable.redraw();
	}

	/**
	 * Supprime
	 * 
	 * @param event
	 */
	@UiHandler("deleteButton1")
	void onDeleteButton1Click(ClickEvent event) {
		deleteSelectedItems();
	}

	/*
	 * Styles
	 */
	interface SelectionStyle extends CssResource {
		String selectedRow();
	}

	interface TableResources extends CellTable.Resources {
		@Source({ CellTable.Style.DEFAULT_CSS, "BottlesListCellTable.css" })
		TableStyle cellTableStyle();
	}

	/**
	 * The styles applied to the table.
	 */
	interface TableStyle extends CellTable.Style {
	}

	@UiFactory
	CellTable<TastingProxy> createCellTable() {
		CellTable.Resources resources = GWT.create(TableResources.class);
		return new CellTable<TastingProxy>(20, resources);
	}
}
